package com.ls.service.impl;

import com.ls.base.BaseResult;
import com.ls.base.BaseResultUtil;
import com.ls.constant.SystemConstants;
import com.ls.controller.model.PermissionModel;
import com.ls.entity.SysUser;
import com.ls.exception.CommonExceptionEnums;
import com.ls.mapper.SysPermissionMapper;
import com.ls.service.ILoginService;
import com.ls.service.ISysUserService;
import com.ls.utils.JsonUtils;
import com.ls.utils.TokenUtils;
import com.ls.utils.redis.RedisClient;
import com.ls.utils.rsa.RsaUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

import static com.ls.utils.redis.RedisKey.ROLE_PERMISSION_KEY;


/**
 * @ClassName LoginServiceImpl
 * @Description 登录相关逻辑
 * @Author TangQuanBin
 * @Date 2019/9/15 9:05
 * @Version 1.0
 **/
@Service
public class LoginServiceImpl implements ILoginService {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoginServiceImpl.class);
    /**
     * 用户接口
     */
    @Autowired
    private ISysUserService sysUserService;

    /**
     * redis 相关
     */
    @Autowired
    private RedisClient redisClient;

    @Autowired
    private SysPermissionMapper sysPermissionMapper;

    /**
     * redis 超时时间
     */
    @Value("${user.login-expire-time}")
    private int expireTime;

    /**
     * shiro登录有效时间
     */
    @Value("${shiro.timeout}")
    private int timeOut;

    /**
     * RSA私钥
     */
    @Value("${RSA.privateKey}")
    private String privateKey;

    /**
     * RSA公钥
     */
    @Value("${RSA.publicKey}")
    private String publicKey;

    /**
     * 登录接口
     *
     * @param account  账户
     * @param password 密码
     * @return
     */
    @Override
    public BaseResult login(String account, String password) {

        try {
            SysUser user = sysUserService.findUserByAccount(account);
            if (user == null) {
                return BaseResultUtil.error(CommonExceptionEnums.UNDEFINED_EXCEPTION.getCode(),
                        "系统无此用户");
            }
//            String userPwd = getRsaDecryStr(user.getPassword());
            String userPwd = user.getPassword();
            //小项目不做加解密
//            String loginPwd = getRsaDecryStr(password);
            String loginPwd = password;
            if (!userPwd.equals(loginPwd)) {
                return BaseResultUtil.error(CommonExceptionEnums.UNDEFINED_EXCEPTION.getCode(),
                        "密码错误");
            }
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            Session oldSession = subject.getSession();
            // 重置session
            final LinkedHashMap<Object, Object> attributes = new LinkedHashMap<>();
            Collection<Object> keys = oldSession.getAttributeKeys();
            for (Object key : keys) {
                final Object value = oldSession.getAttribute(key);
                if (value != null) {
                    attributes.put(key, value);
                }
            }
            oldSession.stop();
            Session session = subject.getSession();
            for (final Object key : attributes.keySet()) {
                session.setAttribute(key, attributes.get(key));
            }
            if (!subject.isAuthenticated()) {
                UsernamePasswordToken shiroToken = new UsernamePasswordToken(account, userPwd);
                subject.login(shiroToken);
                // shiro设置一次登录session的有效时间
                session.setTimeout(timeOut);

                session.setAttribute(SystemConstants.SESSION_USER, user);
                session.setAttribute(SystemConstants.SESSION_USER_ROLE_ID, user.getRoleId());
                session.setAttribute(SystemConstants.SESSION_ID, session.getId());

                //===========（目的：商城调用礼券接口统一带token获取用户）=============/

                //将生成token放入redis，key为sessionId
                String redisToken = TokenUtils.generateToken(user.getUserId(), user.getAccount(), "");
                String sessionId = (String) session.getId();
                redisClient.save(sessionId,redisToken);
                redisClient.setExpireTime(sessionId, expireTime);
                //将用户信息放入Redis，key为token
                boolean result = redisClient.save(redisToken, JsonUtils.toJsonString(user));

                redisClient.setExpireTime(redisToken, expireTime);

                //获取用户权限返回前端
                Long roleId = user.getRoleId();
                if(roleId==null){
                    LOGGER.error("用户_{}登录shiro认证异常,异常信息:{}", account, "登录用户无对应角色！");
                }
                List<PermissionModel> permissionList = redisClient.getList(ROLE_PERMISSION_KEY, String.valueOf(roleId),PermissionModel.class);
                if(permissionList==null || permissionList.size() ==0){
                    LOGGER.error("缓存角色权限出现问题");
                    permissionList = sysPermissionMapper.getRolePermission(roleId);
                }
                LOGGER.info("=====用户{}开始登录，redis保存用户信息状态={}",user.getNickName(),result);
                // 必要值返回给前端
                Map<String, Object> map = new HashMap<>(5);
                user.setPassword(null);
                map.put("permissionList", permissionList);
                map.put(SystemConstants.SESSION_USER, user);
                map.put(SystemConstants.SYS_TOKEN, redisToken);
                return BaseResultUtil.success(map);
            }
        } catch (AuthenticationException e) {
            LOGGER.error("用户_{}登录shiro认证异常,异常信息:{}", account, e);
            return BaseResultUtil.error(CommonExceptionEnums.LOGIN_OUT_OF_DATE.getCode(),
                    CommonExceptionEnums.LOGIN_OUT_OF_DATE.getMessage());
        } catch (Exception e) {
            LOGGER.error("用户_{}登录异常,异常信息:{}", account, e);
            return BaseResultUtil.error(CommonExceptionEnums.UNDEFINED_EXCEPTION.getCode(),
                    "登录异常");
        }
        return BaseResultUtil.error(CommonExceptionEnums.UNDEFINED_EXCEPTION.getCode(),
                "登录失败");
    }


    /**
     * RSA解密
     *
     * @param password 需要解密的密码
     * @return 解密后的密码
     */
    public String getRsaDecryStr(String password) {
        //将加密字符串解密并返回
        String replaceStr = password.replace(" ", "+");
        return RsaUtils.decryptDataOnJava(replaceStr, privateKey);
    }



}
